/**
  ETFAna project, Anyang Normal University && IMP-CAS
  \class ETFTrackManager
  \brief a manager class holding the fitted tracks and the track finders.
  \author SUN Yazhou, asia.rabbit@163.com
  \since 2021-11-01
  \date 2023-05-28 last modified
  \attention
  changelog
  <table>
  <tr>  <th>Date         <th>Author      <th>Description                   </tr>
  <tr>  <td>2021-11-01   <td>Asia Sun    <td>file created                  </tr>
  <tr>  <td>2023-05-28   <td>Asia Sun    <td>mpostMagTrker added           </tr>
  </table>

  \copyright Copyright (c) 2021-2024 Anyang Normal U. && IMP-CAS with LGPLv3 LICENSE
*/

#include "ETFTrackManager.h"
#include "ETFTaTracker.h"
#include "ETFPostMagTracker.h"
#include "ETFGlobalTracker.h"
#include "ETFMsg.h"

ETFTrackManager *ETFTrackManager::fInstance = nullptr;

ETFTrackManager::ETFTrackManager() : ETFVTrackManager(), fPreTaTracker(nullptr),
fPostTaTracker(nullptr), fPostMagTracker(nullptr), fmPostMagTracker(nullptr),
fGlobalTracker(nullptr), fTa4Tracker(nullptr){
  char tkru[] = "preTaTracker", tkrd[] = "postTaTracker";
  char tkrm[] = "postMagTracker", tkrmm[] = "mpostMagTracker";
  char tkrg[] = "globalTracker", tkr4[] = "ta4Tracker";
  const ETFYaml &cc = *fcfg;
  // configure preTaTracker //
  if(cc[tkru]) fPreTaTracker = new ETFTaTracker(tkru,
    cc[tkru]["dcs"].as<vector<string>>(), cc[tkru]["t0"].as<string>());
  // configure postTaTracker //
  if(cc[tkrd]) fPostTaTracker = new ETFTaTracker(tkrd,
    cc[tkrd]["dcs"].as<vector<string>>(), cc[tkrd]["t0"].as<string>());
  // configure postMagTracker //
  if(cc[tkrm]) fPostMagTracker = new ETFPostMagTracker(tkrm,
    cc[tkrm]["dcs"].as<vector<string>>(),
    cc[tkrm]["tofw"] ? cc[tkrm]["tofw"].as<string>() : "",
    cc[tkrm]["t0"] ? cc[tkrm]["t0"].as<string>() : "");
  // configure postMagTracker-m - an auxillary tracker to postMagTrker //
  if(cc[tkrmm]) fmPostMagTracker = new ETFPostMagTracker(tkrmm,
    cc[tkrmm]["dcs"].as<vector<string>>(),
    cc[tkrm]["tofw"] ? cc[tkrm]["tofw"].as<string>() : "",
    cc[tkrm]["t0"] ? cc[tkrm]["t0"].as<string>() : "");
  // configure globalTracker //
  if(cc[tkrg]){
    string t1 = "";
    if(cc[tkrg]["t1"]) t1 = cc[tkrg]["t1"].as<string>();
    fGlobalTracker = new ETFGlobalTracker(tkrg,
      cc[tkrg]["dcs"].as<vector<string>>(), cc[tkrg]["t0"].as<string>(), t1);
  } // end if
  // configure ta4Tracker //
  if(cc[tkr4]){
    string t1 = "";
    if(cc[tkr4]["t1"]) t1 = cc[tkr4]["t1"].as<string>();
    fTa4Tracker = new ETFTaTracker(tkr4, cc[tkr4]["dcs"].as<vector<string>>(),
      cc[tkr4]["t0"].as<string>(), t1);
  } // end if

  // if(!fPreTaTracker && !fPostTaTracker && !fPostMagTracker && !fmPostMagTracker &&
  //     !fGlobalTracker && !fTa4Tracker)
  //   ETFMsg::Error("ETFTrackManager", "ctor: all trackers are nullptr");
  if(fGlobalTracker){
    if(!fPreTaTracker || !fPostTaTracker)
      ETFMsg::Error("ETFTrackManager",
        "ctor: global trker is present, while pre and/or post trker is/are not");
    fGlobalTracker->SetChiPD(fPreTaTracker->GetChiPD(), fPostTaTracker->GetChiPD());
    fGlobalTracker->SetD2THREPD(fPreTaTracker->GetD2THREPD(), fPostTaTracker->GetD2THREPD());
  } // end if
} // end ctor

ETFTrackManager::~ETFTrackManager(){
  if(fPreTaTracker) delete fPreTaTracker;
  if(fPostTaTracker) delete fPostTaTracker;
  if(fPostMagTracker) delete fPostMagTracker;
  if(fmPostMagTracker) delete fmPostMagTracker;
  if(fGlobalTracker) delete fGlobalTracker;
  if(fTa4Tracker) delete fTa4Tracker;
} // end dtor

void ETFTrackManager::SetDebug(bool opt){
  if(fPreTaTracker) fPreTaTracker->SetDebug(opt);
  if(fPostTaTracker) fPostTaTracker->SetDebug(opt);
  if(fPostMagTracker) fPostMagTracker->SetDebug(opt);
  if(fmPostMagTracker) fmPostMagTracker->SetDebug(opt);
  if(fGlobalTracker) fGlobalTracker->SetDebug(opt);
  if(fTa4Tracker) fTa4Tracker->SetDebug(opt);
} // end member function SetDebug

ETFTrackManager *ETFTrackManager::Instance(){
  if(!fInstance) fInstance = new ETFTrackManager();
  return fInstance;
} // end member function Instance

// register tracks to main TTree
void ETFTrackManager::Register(){
  if(fPreTaTracker) fPreTaTracker->Register();
  if(fPostTaTracker) fPostTaTracker->Register();
  if(fPostMagTracker) fPostMagTracker->Register();
  if(fmPostMagTracker) fmPostMagTracker->Register();
  if(fGlobalTracker) fGlobalTracker->Register();
  if(fTa4Tracker) fTa4Tracker->Register();
} // end member function Register

// do the overall tracking
void ETFTrackManager::Map(){
  if(!fHasMapped) fHasMapped = true;
  else return;
  // do the preliminary tracking //
  if(fPreTaTracker) fPreTaTracker->Map();
  if(fPostTaTracker) fPostTaTracker->Map();
  if(fPostMagTracker) fPostMagTracker->Map();
  if(fmPostMagTracker) fmPostMagTracker->Map();
  // then refine the tracking with ETFGlobalTracker //
  if(fPreTaTracker && fPostTaTracker && fPostMagTracker && fGlobalTracker){
    if(1 == fPostMagTracker->GetNofTracks() && fPostTaTracker->GetNofTracks() >= 1
    && fPreTaTracker->GetNofTracks() >= 1){
      fGlobalTracker->SetPostMagTrk(fPostMagTracker->GetTrack(0));
      fGlobalTracker->Map();
    } // end if
    // replace X tracks in pre/post-TaTrackers with ameliorated global ones
    if(fGlobalTracker->GetNofTracks())
      fGlobalTracker->UpdateTracks(fPreTaTracker, fPostTaTracker);
  } // end outer if
  if(fTa4Tracker) fTa4Tracker->Map();
} // end member function Map

// do the overall 3D tracking
void ETFTrackManager::Map3D(){
  if(!fHasMapped3D) fHasMapped3D = true;
  else return;

  Map(); // do the 2D X tracking first, and ameliorate the tracking
  if(fPostMagTracker) fPostMagTracker->Map3D(); // do the Y tracking altogether
  if(fmPostMagTracker) fmPostMagTracker->Map3D(); // do the Y tracking altogether
} // end member function Map

void ETFTrackManager::Draw(){
  if(fPreTaTracker) fPreTaTracker->Draw();
  if(fPostTaTracker) fPostTaTracker->Draw();
  if(fTa4Tracker) fTa4Tracker->Draw();
  // if(fGlobalTracker) fGlobalTracker->Draw();
  if(fPostMagTracker) fPostMagTracker->Draw();
  if(fmPostMagTracker) fmPostMagTracker->Draw();
} // end member function Draw

void ETFTrackManager::Write(){
  // fPreTaTracker->Write();
  // fPostTaTracker->Write();
  if(fGlobalTracker) fGlobalTracker->Write();
  if(fPostMagTracker) fPostMagTracker->Write();
  if(fmPostMagTracker) fmPostMagTracker->Write();
  if(fTa4Tracker) fTa4Tracker->Write();
} // end member function Write

void ETFTrackManager::Reset(){
  if(fPreTaTracker) fPreTaTracker->Reset();
  if(fPostTaTracker) fPostTaTracker->Reset();
  if(fPostMagTracker) fPostMagTracker->Reset();
  if(fmPostMagTracker) fmPostMagTracker->Reset();
  if(fGlobalTracker) fGlobalTracker->Reset();
  if(fTa4Tracker) fTa4Tracker->Reset();
  if(fHasMapped) fHasMapped = false;
  if(fHasMapped3D) fHasMapped3D = false;
} // end member function Write

void ETFTrackManager::Print(){
  if(fPreTaTracker) fPreTaTracker->Print();
  if(fPostTaTracker) fPostTaTracker->Print();
  if(fPostMagTracker) fPostMagTracker->Print();
  if(fmPostMagTracker) fmPostMagTracker->Print();
  if(fGlobalTracker) fGlobalTracker->Print();
  if(fTa4Tracker) fTa4Tracker->Print();
} // end member function Print

int ETFTrackManager::GetNofTracks(TrackType type) const{
  int cnt = 0;
  bool isV = TrackType::kV == type;
  bool isX = TrackType::kX == type;

  if(!isV && fPreTaTracker) cnt += fPreTaTracker->GetNofTracks(type);
  if(!isV && fPostTaTracker) cnt += fPostTaTracker->GetNofTracks(type);
  if(fPostMagTracker) cnt += fPostMagTracker->GetNofTracks(type);
  if(fmPostMagTracker) cnt += fmPostMagTracker->GetNofTracks(type);
  if(isX && fGlobalTracker) cnt += fGlobalTracker->GetNofTracks(type);
  if(!isV && fTa4Tracker) cnt += fTa4Tracker->GetNofTracks(type);
  return cnt;
} // end member function GetNofTracks

int ETFTrackManager::GetNof3DTracks() const{
  int cnt = 0;
  if(fPreTaTracker) cnt += fPreTaTracker->GetNof3DTracks();
  if(fPostTaTracker) cnt += fPostTaTracker->GetNof3DTracks();
  if(fPostMagTracker) cnt += fPostMagTracker->GetNof3DTracks();
  if(fmPostMagTracker) cnt += fmPostMagTracker->GetNof3DTracks();
  // if(fGlobalTracker) cnt += fGlobalTracker->GetNof3DTracks();
  if(fTa4Tracker) cnt += fTa4Tracker->GetNof3DTracks();
  return cnt;
} // end member function GetNof3DTracks
